#ifndef XG_CMD_CPP
#define XG_CMD_CPP
////////////////////////////////////////////////////////
#include "../cmd.h"
#include "../../clib/utils.h"

void cmdx::puts(const string& msg)
{
	::puts(stdx::syscode(msg).c_str());
}
void cmdx::printf(const char* fmt, ...)
{
	string str;
	va_list args;

	va_start(args, fmt);
	stdx::vformat(str, fmt, args);
	va_end(args);

	str = stdx::syscode(str);
	fwrite(str.c_str(), 1, str.length(), stdout);
}
bool cmdx::CheckCommand(const char* fmt, ...)
{
	int n;
	string str;
	va_list args;

	str.clear();
	va_start(args, fmt);
	n = stdx::vformat(str, fmt, args);
	va_end(args);

	printf("%s", str.c_str());
	fflush(stdout);

	while (true)
	{
		n = getch();

		if (n == 'Y' || n == 'y')
		{
			SetConsoleTextColor(eGREEN);
			printf(" (YES)\n");
			SetConsoleTextColor(eWHITE);

			return true;
		}
		else if (n == 'N' || n == 'n')
		{
			SetConsoleTextColor(eRED);
			printf(" (NO)\n");
			SetConsoleTextColor(eWHITE);

			return false;
		}
	}

	return false;
}
void cmdx::PrintHexData(const void* msg, int len)
{
	int i = 0;
	int n = 0;
	u_char buffer[32] = {0};
	u_char* data = (u_char*)(msg);
	
	for (i = 0; i < len; i++)
	{
		if (i % 16 == 0)
		{
			if (n == 16)
			{
				n = 0;
				SetConsoleTextColor(eGREEN);
				printf(" %s\n", buffer);
				SetConsoleTextColor(eWHITE);
				memset(buffer, 0, sizeof(buffer));
			}

			SetConsoleTextColor(eYELLOW);
			printf("[%04X] ", i);
			SetConsoleTextColor(eWHITE);
		}

		printf("%02X ", data[i] % 256);

		buffer[n++] = (data[i] > 0X1F && data[i] < 0X7F) ? data[i] : '.';
	}
	
	if (n > 0)
	{
		for (i = n; i < 16; i++) printf("   ");	

		SetConsoleTextColor(eGREEN);
		printf(" %s\n", buffer);
		SetConsoleTextColor(eWHITE);
	}
}

int cmdx::SelectCommand(const vector<string>& menus, const char* msg)
{
	string str;
	int ch = 0;
	int cnt = menus.size();


	if (msg && *msg)
	{
		printf(" %s\n", msg);
		puts("-----------------------------------------");
	}

	for (int i = 0; i < cnt; i++)
	{
		printf(" %d.%s\n", i + 1, menus[i].c_str());
	}

	puts("------------------------------------------");
	printf(" press numeric key to select the menu : ");

	while (true)
	{
		ch = getch();
		ch -= '0';

		if (ch >= 1 && ch <= cnt)
		{
			printf("%d\n", ch);

			return ch;
		}
	}

	return 0;
}


int proc::argc()
{
	return Process::GetCmdParamCount();
}
const char* proc::argv(int index)
{
	return Process::GetCmdParam(index);
}
const char* proc::argv(const char* key)
{
	return Process::GetCmdParam(key);
}
Process* proc::init(int argc, char** argv)
{
	return Process::Instance(argc, argv);
}

string proc::pwd()
{
	return Process::GetCurrentDirectory();
}
string proc::pwd(const string& path)
{
	return Process::SetCurrentDirectory(path) ? path : pwd();
}

string proc::home()
{
	return Process::GetEnv("HOME");
}
string proc::exepath()
{
	string path;

	Process::GetProcessExePath(path);

	return std::move(path);
}
string proc::exename()
{
	return stdx::GetFileNameFromPath(exepath());
}
string proc::appname()
{
	return Process::GetAppname();
}
string proc::env(const string& key)
{
	return Process::GetEnv(key);
}
string proc::env(const string& key, const string& val)
{
	Process::SetEnv(key, val);

	return Process::GetEnv(key);
}

long proc::tid()
{
	return GetCurrentThreadId();
}
void proc::daemon()
{
	Process::InitDaemon();
}
PROCESS_T proc::pid()
{
	return Process::GetCurrentProcess();
}
void proc::exit(int code)
{
	SystemExit(code);
}
void proc::wait(PROCESS_T pid)
{
	Process::Wait(pid);
}
void proc::kill(PROCESS_T pid, int flag)
{
	Process::Kill(pid, flag);
}

vector<ProcessData> proc::ps()
{
	vector<ProcessData> vec;

	Process::GetSystemProcessList(vec);

	return std::move(vec);
}
vector<ProcessData> proc::ps(string name)
{
	vector<ProcessData> vec;

	Process::GetSystemProcessListByName(vec, name);

	return std::move(vec);
}

string path::name(const string& path)
{
	return stdx::GetFileNameFromPath(path);
}
string path::parent(const string& path)
{
	return stdx::GetParentPath(path);
}
string path::extname(const string& path)
{
	return stdx::GetExtNameFromPath(path);
}

string path::cat(const string& path)
{
	string content;

	stdx::GetFileContent(content, path);

	return std::move(content);
}
bool path::copy(const string& src, const string& dest)
{
	return CloneFile(src.c_str(), dest.c_str()) >= 0;
}
bool path::rename(const string& src, const string& dest)
{
	return Rename(src.c_str(), dest.c_str()) >= 0;
}
sp<XFile> path::create(const string& path, bool clear)
{
	int flag = GetPathType(path.c_str());

	if (flag == ePATH) return NULL;

	if (flag == eNONE) clear = true;

	sp<XFile> file = newsp<XFile>();

	return file->open(path, clear ? eCREATE : eWRITE) ? file : sp<XFile>();
}
sp<XFile> path::open(const string& path, E_OPEN_MODE mode)
{
	sp<XFile> file = newsp<XFile>();

	return file->open(path, mode) ? file : sp<XFile>();
}

int path::type(const string& path)
{
	return GetPathType(path.c_str());
}
long path::size(const string& path)
{
	return GetFileLength(path.c_str());
}
bool path::mkdir(const string& path)
{
	return CreateFolder(path.c_str()) >= 0;
}
bool path::isdir(const string& path)
{
	return GetPathType(path.c_str()) == ePATH;
}
bool path::isfile(const string& path)
{
	return GetPathType(path.c_str()) == eFILE;
}
bool path::exists(const string& path)
{
	return GetPathType(path.c_str()) >= ePATH;
}
bool path::remove(const string& path)
{
	if (GetPathType(path.c_str()) == ePATH)
	{
#ifdef XG_LINUX
		return cmdx::RunCommand(stdx::format("rm -rf %s > /dev/null 2>&1", stdx::quote(path).c_str())) >= 0;
#else
		return cmdx::RunCommand(stdx::format("rd /s /q %s", stdx::quote(path).c_str())) >= 0;
#endif
	}

	return RemoveFile(path.c_str()) >= 0;
}
time_t path::mtime(const string& path)
{
	return GetFileUpdateTime(path.c_str());
}
time_t path::mtime(const string& path, const time_t& tm)
{
	SetFileUpdateTime(path.c_str(), &tm);

	return GetFileUpdateTime(path.c_str());
}
vector<string> path::dir(const string& path, bool file)
{
	vector<string> vec;

	stdx::GetFolderContent(vec, path, file ? eFILE : ePATH);

	return std::move(vec);
}
vector<string> path::find(const string& path, const string& filter)
{
	vector<string> vec;

	stdx::FindFile(vec, path, filter);

	return std::move(vec);
}

#ifdef XG_LINUX

int cmdx::RunCommand(const string& cmd, char* buffer, int size, bool hidden, bool transcode)
{
	FILE* fp = popen(stdx::syscode(cmd).c_str(), "r");

	if (fp == NULL) return XG_SYSERR;

	if (buffer) size = fread(buffer, 1, size - 1, fp);

	pclose(fp);

	if (size < 0) return XG_SYSERR;

	if (buffer) buffer[size] = 0;

	return size;
}

#else

int cmdx::RunCommand(const string& cmd, char* buffer, int size, bool hidden, bool transcode)
{
	HANDLE hRead = NULL;
	HANDLE hWrite = NULL;
	SECURITY_ATTRIBUTES sa;
	string tmp = stdx::syscode(cmd);
	SmartBuffer args((tmp.length() + 0xFF) << 1);

	snprintf(args.str(), args.size(), "cmd /c %s", stdx::quote(tmp).c_str());

	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);

	if (CreatePipe(&hRead, &hWrite, &sa, XG_MEMFILE_MAXSZ))
	{
		STARTUPINFOA si;
		PROCESS_INFORMATION pi;

		memset(&si, 0, sizeof(si));
		memset(&pi, 0, sizeof(pi));

		si.cb = sizeof(si);
		si.hStdError = hWrite;
		si.hStdOutput = hWrite;
		si.wShowWindow = hidden ? SW_HIDE : SW_SHOW;
		si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

		if (CreateProcessA(NULL, args.str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
		{
			DWORD readed = 0;

			WaitForSingleObject(pi.hProcess, INFINITE);
			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
			CloseHandle(hWrite);

			if (buffer == NULL)
			{
				CloseHandle(hRead);

				return 0;
			}

			int len = ReadFile(hRead, buffer, size - 1, &readed, NULL) ? readed : XG_ERROR;

			if (len < 0 && GetLastError() == ERROR_BROKEN_PIPE) len = 0;

			CloseHandle(hRead);

			if (len >= 0)
			{
				buffer[len] = 0;

				if (len <= 1) return len;

				if (transcode && len <= 1024 * 1024 && len == strlen(buffer))
				{
					string tmp = stdx::utfcode(buffer);

					if (tmp.length() > 0 && tmp.length() < size)
					{
						memcpy(buffer, tmp.c_str(), tmp.length());
						buffer[tmp.length()] = 0;

						return tmp.length();
					}
				}

				return len;
			}
		}
		else
		{
			CloseHandle(hWrite);
			CloseHandle(hRead);
		}
	}

	return XG_SYSERR;
}

#endif

////////////////////////////////////////////////////////
#endif